use crate::gslb::{
    Server, PROTO_COAP, PROTO_HTTP, PROTO_HTTPS, PROTO_MQTT, PROTO_MQTTS, PROTO_NTP, PROTO_UKEEP,
};
use alloc::vec::Vec;
use core::ffi::{c_char, c_uint};
use embed_std::util::copy_str_to_cslice;

pub type iot_err_code_e = c_uint;
pub const iot_err_code_e_RC_OK: iot_err_code_e = 0;
pub const iot_err_code_e_RC_FAIL: iot_err_code_e = 1;
pub const iot_err_code_e_RC_ONLY_SINGLE_INSTNACE: iot_err_code_e = 2;
pub const iot_err_code_e_RC_INVALID_PARAMS: iot_err_code_e = 3;
pub const iot_err_code_e_RC_NOT_INITED: iot_err_code_e = 4;
pub const iot_err_code_e_RC_NO_ACTIVATE: iot_err_code_e = 5;
pub const iot_err_code_e_RC_ACTIVATED: iot_err_code_e = 6;
pub const iot_err_code_e_RC_DISCONNECTED: iot_err_code_e = 7;
pub const iot_err_code_e_RC_CONNECT_MQTT_SERVER_FAIL: iot_err_code_e = 8;
pub const iot_err_code_e_RC_INIT_MQTT_FAIL: iot_err_code_e = 9;
pub const iot_err_code_e_RC_SERIALIZE_FAIL: iot_err_code_e = 10;
pub const iot_err_code_e_RC_MQTT_SUBSCRIBE_FAIL: iot_err_code_e = 11;
pub const iot_err_code_e_RC_MQTT_PUBLISH_FAIL: iot_err_code_e = 12;
pub const iot_err_code_e_RC_BIND_FAIL: iot_err_code_e = 13;
pub const iot_err_code_e_RC_BOUND: iot_err_code_e = 14;
pub const iot_err_code_e_RC_PROTOCOL_BUILD_FAIL: iot_err_code_e = 15;
pub const iot_err_code_e_RC_PROTOCOL_FAIL: iot_err_code_e = 16;
pub const iot_err_code_e_RC_ENCRYPT_FAIL: iot_err_code_e = 17;
pub const iot_err_code_e_RC_HTTP_BUILD_FAIL: iot_err_code_e = 18;
pub const iot_err_code_e_RC_HTTP_REQUEST_FAIL: iot_err_code_e = 19;
pub const iot_err_code_e_RC_HTTP_RESPONSE_FAIL: iot_err_code_e = 20;
pub const iot_err_code_e_RC_HTTP_INVALID_RESPONSE: iot_err_code_e = 21;
pub const iot_err_code_e_RC_NTP_FAIL: iot_err_code_e = 22;
pub const iot_err_code_e_RC_CALL_TIMEOUT: iot_err_code_e = 23;
pub const iot_err_code_e_RC_CALL_ERROR: iot_err_code_e = 24;
pub const iot_err_code_e_RC_TRANSPORT_SEND_FAIL: iot_err_code_e = 25;
pub const iot_err_code_e_RC_GET_SERVER_LIST_FAIL: iot_err_code_e = 26;
pub const iot_err_code_e_RC_IOT_PLATFORM_BASE_ERR: iot_err_code_e = 1000;

pub const SERVER_TYPE_UNKNOWN: u32 = 0;
pub const SERVER_TYPE_DEVICE_GW: u32 = 1;
pub const SERVER_TYPE_API_GW: u32 = 2;
pub const SERVER_TYPE_NTP: u32 = 3;
pub const SERVER_TYPE_OTA: u32 = 4;
pub const SERVER_TYPE_KEEP: u32 = 5;

pub const PROTO_TYPE_UNKNOWN: u32 = 0;
pub const PROTO_TYPE_HTTP: u32 = 1;
pub const PROTO_TYPE_HTTPS: u32 = 2;
pub const PROTO_TYPE_MQTT: u32 = 3;
pub const PROTO_TYPE_MQTTS: u32 = 4;
pub const PROTO_TYPE_NTP: u32 = 5;
pub const PROTO_TYPE_COAP: u32 = 6;
pub const PROTO_TYPE_UKEEP: u32 = 7;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct server_address_t {
    pub ip: [c_char; 32usize],
    pub domain: [c_char; 32usize],
    pub server_type: u8,
    pub proto_type: u8,
    pub priority: u8,
    pub reserve: u8,
}

fn parse_protocol(p: &str) -> (u8, u8) {
    let infos: [(&str, u32, u32); 7] = [
        (PROTO_HTTPS, SERVER_TYPE_API_GW, PROTO_TYPE_HTTPS),
        (PROTO_HTTP, SERVER_TYPE_API_GW, PROTO_TYPE_HTTP),
        (PROTO_MQTTS, SERVER_TYPE_DEVICE_GW, PROTO_TYPE_MQTTS),
        (PROTO_MQTT, SERVER_TYPE_DEVICE_GW, PROTO_TYPE_MQTT),
        (PROTO_NTP, SERVER_TYPE_NTP, PROTO_TYPE_NTP),
        (PROTO_COAP, SERVER_TYPE_KEEP, PROTO_TYPE_COAP),
        (PROTO_UKEEP, SERVER_TYPE_KEEP, PROTO_TYPE_UKEEP),
    ];
    for item in infos {
        if p == item.0 {
            return (item.1 as u8, item.2 as u8);
        }
    }
    (SERVER_TYPE_UNKNOWN as u8, PROTO_TYPE_UNKNOWN as u8)
}

impl From<&Server> for server_address_t {
    fn from(value: &Server) -> Self {
        let mut v: Self = unsafe { core::mem::zeroed() };
        let items: Vec<&str> = value.protocol().split(";").collect();
        if items.len() > 0 {
            (v.server_type, v.proto_type) = parse_protocol(items[0]);
        } else {
            v.server_type = SERVER_TYPE_UNKNOWN as u8;
            v.proto_type = PROTO_TYPE_UNKNOWN as u8;
        }
        v.priority = value.priority();
        copy_str_to_cslice(value.domain.as_str(), &mut v.domain);
        copy_str_to_cslice(value.ip.as_str(), &mut v.ip);
        v
    }
}

extern "C" {
    #[doc = " 外部提供: 获取、保存配置信息"]
    pub fn get_iot_config() -> *mut iot_param_t;
}
extern "C" {
    pub fn save_iot_config(config: *mut iot_param_t);
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct iot_param_t {
    pub device_uid: [c_char; 64usize],
    pub product_code: [c_char; 64usize],
    pub secret: [c_char; 64usize],
    pub activate_secret: [c_char; 64usize],
    pub sn: [c_char; 64usize],
    pub servers: [server_address_t; 6usize],
}
